package com.exchange.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.exchange.entity.model.ReservationModel;
import com.exchange.entity.pojo.*;
import com.exchange.entity.vo.MapVo;
import com.exchange.entity.vo.StarsAddressVo;
import com.exchange.mapper.MapMapper;
import com.exchange.service.*;
import com.exchange.until.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author Administrator
 * @description 针对表【map】的数据库操作Service实现
 * @createDate 2024-04-25 20:02:10
 */
@Slf4j
@Service
public class MapServiceImpl extends ServiceImpl<MapMapper, Map>
        implements MapService {
    @Autowired
    private MapMapper mapMapper;
    @Autowired
    private StarsAddressService starsAddressService;
    @Autowired
    private UserService userService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ReservationRecordService reservationRecordService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private UserDetailService userDetailService;
    @Autowired
    private DetailPowerService detailPowerService;

    @Override
    public List<MapVo> getAllPoint() {
        List<MapVo> mapVos = this.mapMapper.getAllPoint();
        return mapVos;
    }

    /**
     * 查询地址列表由两个列表组成
     * 1、收藏表中获取的收藏地址
     * 2、从redis中拿取的常用地址
     * 两个列表封装成map传给前端
     *
     * @param token redis中的用户名字
     * @return
     */
    @Override
    public Result<java.util.Map<String, List<StarsAddressVo>>> getAddressAuxi(String token) {
        String s = redisTemplate.opsForValue().get("user:login" + token);
        User user = JSON.parseObject(s, User.class);
        if (ObjectUtil.isEmpty(user)) {
            return Result.error("用户信息查询失败！");
        }
        log.info("id------>{}", user.getId());
        List<StarsAddressVo> starsAddressVos = this.starsAddressService.getAllAddressByUid(user.getId());
        if (starsAddressVos.size() == 0) {
            return Result.error("收藏地址查询失败");
        }
        //redis获取常用地址
        Set<ZSetOperations.TypedTuple<String>> typedTuples = this.redisTemplate.opsForZSet().reverseRangeWithScores("user:address" + user.getId(), 0, 100);
        HashMap<String, List<StarsAddressVo>> stringListHashMap = new HashMap<>();
        stringListHashMap.put("stars", starsAddressVos);
        ArrayList<StarsAddressVo> starsAddressVos1 = new ArrayList<>();
        if (ObjectUtil.isEmpty(typedTuples)) {
            stringListHashMap.put("usual", starsAddressVos1);
            return Result.success(stringListHashMap);
        }
        assert typedTuples != null;
        for (ZSetOperations.TypedTuple redisMessage : typedTuples) {
            starsAddressVos1.add(JSON.parseObject(redisMessage.getValue().toString(), StarsAddressVo.class));
        }
        stringListHashMap.put("usual", starsAddressVos1);
        return Result.success(stringListHashMap);
    }

    /**
     * 根据token拿到用户的id   该id将作为唯一的索引来查询redis中只对当前设备持久化的常用列表
     * 1、先查询用户id，根据用户id查询redis中的数据
     * 2、根据用户输入的address来找寻距离最近的地址（因为是模糊）
     * 3、将该地址封装成StarsAddressVo类放到redis中的zSet中存储，并设置score分数作为排序使用
     * 4、如果存在则增加分数  不存在则新增 分数设置为1
     *
     * @param token   当前登录用户的信息
     * @param address 用户当前搜索的地址
     * @return
     */
    @Override
    public String searchTheFrame(String token, String address) {
        log.info("token---->{}", token);
        String s = this.redisTemplate.opsForValue().get("user:login" + token);
        User user = JSON.parseObject(s, User.class);
        log.info("user------->{}", user);
        if (ObjectUtil.isEmpty(user)) {
            return "用户信息查询失败";
        }
        log.info("address---->{}", address);
        //根据用户输入的模糊地址来查询真正的地图标记点位（该点位在假设中是唯一的）
        StarsAddressVo one = this.starsAddressService.getStarsAddress(address);
        one.setMid(one.getId());
        one.setUid(user.getId());
        if (ObjectUtil.isEmpty(one)) {
            //地址不存在,不予保存
            return "地址不存在";
        }
        boolean b = false;
        Set<String> range = this.redisTemplate.opsForZSet().range("user:address" + user.getId(), 0, -1);
        for (String currentS : range) {
            StarsAddressVo starsAddressVo = JSON.parseObject(currentS, StarsAddressVo.class);
            if (one.getAddress().equals(starsAddressVo.getAddress())) {
                //递增当前元素的分数
                this.redisTemplate.opsForZSet().incrementScore("user:address" + user.getId(), JSON.toJSONString(one), 1);
                b = true;
            }
        }
        if (!b) {
            //加入新元素，初始值设置为1
            this.redisTemplate.opsForZSet().add("user:address" + user.getId(), JSON.toJSONString(one), 1);
        }
        return "ok";
    }

    /**
     * 查看当前用户是否有预约，如果没有则交由rabbitmq去操作
     *
     * @param id
     * @param token
     * @return
     */
    @Override
    public Result<String> reservation(Long id, String token) {
        String s = this.redisTemplate.opsForValue().get("user:login" + token);
        User user = JSON.parseObject(s, User.class);
        log.info("user----------->{}", user);
        QueryWrapper<ReservationRecord> reservationRecordQueryWrapper = new QueryWrapper<>();
        reservationRecordQueryWrapper.eq("uid", user.getId());
        reservationRecordQueryWrapper.eq("status",2);
        ReservationRecord one = this.reservationRecordService.getOne(reservationRecordQueryWrapper);
        if (!ObjectUtil.isEmpty(one)) {
            //用户存在预约
            return Result.success("您当前有预约");
        }
        ReservationModel reservationModel = new ReservationModel();
        reservationModel.setUid(user.getId());
        reservationModel.setDtpid(id);
        DetailPower detailPower = this.detailPowerService.selectOneByPid(reservationModel.getDtpid());
        if (ObjectUtil.isEmpty(detailPower)) {
            return Result.error("该充电点不存在");
        }
        ReservationRecord reservationRecord = new ReservationRecord();
        reservationRecord.setDpid(detailPower.getId());
        reservationRecord.setUid(reservationModel.getUid());
        //预约进行中
        reservationRecord.setStatus(2);
        reservationRecordService.save(reservationRecord);
        //加入到ttl队列
        this.rabbitTemplate.convertAndSend("ttl-exchange","ttl-queue", JSON.toJSONString(reservationModel));
//        this.redisTemplate.opsForValue().set(JSON.toJSONString(reservationModel),"user:reservation"+token,10, TimeUnit.MINUTES);
        return Result.success("等待电站预约时间~");
    }

    @Override
    public String findAllAvailableBatteryForSelf(String token, Long pid) {
        String s = redisTemplate.opsForValue().get("user:login" + token);
        User user = JSON.parseObject(s, User.class);
        if (ObjectUtil.isEmpty(user)) {
            return "用户信息查询失败！";
        }
        log.info("pid---------->{}", pid);
        QueryWrapper<UserDetail> userDetailQueryWrapper = new QueryWrapper<>();
        userDetailQueryWrapper.eq("uid", user.getId());
        UserDetail userDetail = this.userDetailService.getOne(userDetailQueryWrapper);
        if (ObjectUtil.isEmpty(userDetail)) {
            return "您还未购买套餐";
        }
        int count = this.detailPowerService.selectCountTheReailable(pid, userDetail.getRemark());
        if (count >= 1) {
            return "当前站点有可用电池";
        }
        return "当前站点暂无当前型号可用电池";
    }
}




